#include "serial.hpp"

SerialPort::SerialPort(const std::string& port, int baudrate) 
        : fd_(-1), keep_running_(false)
    {
        // 打开串口设备 (非阻塞模式)
        fd_ = open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (fd_ == -1) 
        {
            throw std::runtime_error("无法打开串口 " + port + ": " + strerror(errno));
        }
        // 配置串口参数
        struct termios tty;
        memset(&tty, 0, sizeof(tty));
        if (tcgetattr(fd_, &tty) != 0) 
        {
            close(fd_);
            throw std::runtime_error("获取串口属性失败: " + std::string(strerror(errno)));
        }
        // 设置波特率
        cfsetospeed(&tty, baudrate);
        cfsetispeed(&tty, baudrate);
        // 通用配置
        tty.c_cflag &= ~PARENB;   // 禁用奇偶校验
        tty.c_cflag &= ~CSTOPB;   // 1位停止位
        tty.c_cflag &= ~CSIZE;    // 清除数据位掩码
        tty.c_cflag |= CS8;       // 8位数据位
        tty.c_cflag &= ~CRTSCTS;  // 禁用硬件流控
        tty.c_cflag |= CREAD | CLOCAL; // 启用接收，忽略控制线
        // 输入模式配置
        tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控
        tty.c_iflag &= ~(INLCR | ICRNL);        // 禁用换行转换
        // 输出模式配置
        tty.c_oflag &= ~OPOST;  // 禁用特殊输出处理
        tty.c_oflag &= ~ONLCR;  // 禁用换行转换
        // 非规范模式配置
        tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        // 超时设置：立即返回，最少读取1个字符
        tty.c_cc[VMIN] = 0;
        tty.c_cc[VTIME] = 10; // 100ms
        // 应用配置
        if (tcsetattr(fd_, TCSANOW, &tty) != 0) 
        {
            close(fd_);
            throw std::runtime_error("设置串口属性失败: " + std::string(strerror(errno)));
        }
        // 清除缓冲区
        tcflush(fd_, TCIOFLUSH);
    }

SerialPort::~SerialPort() 
{
    stop();
    if (fd_ != -1) 
    {
        close(fd_);
        fd_ = -1;
    }
}

ssize_t SerialPort::sendBytes(const std::vector<uint8_t>& data)
{
    if(fd_ == -1)
    {
        throw std::runtime_error("串口未打开");
    }

    ssize_t bytes_written = write(fd_, data.data(), data.size());
    if(bytes_written == -1)
    {
        throw std::runtime_error("发送数据失败：" + std::string(strerror(errno)));
    }
    return bytes_written;
}

ssize_t SerialPort::sendString(const std::string& str)
{
    return sendBytes(std::vector<uint8_t>(str.begin(), str.end()));
}

std::vector<uint8_t> SerialPort::readBytes(size_t max_size)
{
    if(fd_ == -1)
    {
        throw std::runtime_error("串口未打开");
    }
    std::vector<uint8_t> buffer(max_size);
    ssize_t bytes_read = read(fd_, buffer.data(), max_size);

    if(bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
    {
        throw std::runtime_error("读取数据失败：" + std::string(strerror(errno)));
    }

    if(bytes_read <= 0)
    {
        return {};
    }
    // std::cout << "bytes_read: " << bytes_read << std::endl;
    buffer.resize(bytes_read);
    return buffer;
}

// 异步读取示例（需要结合多线程）
void SerialPort::startAsyncRead() 
{
    if (keep_running_) 
    {
        return;
    }
    keep_running_ = true;
    read_thread_ = std::thread([this]() 
    {
        std::vector<uint8_t> receive_buffer;  // 累积接收缓冲区
        size_t header_pos = 0;
        while (keep_running_) 
        {
            auto new_data = readBytes();
            if (!new_data.empty()) 
            {
                receive_buffer.insert(receive_buffer.end(), new_data.begin(), new_data.end());
                
                // 尝试解析状态标志位
                SerialStatus status = parseStatus(receive_buffer);
                if (status.valid) // 保存最新状态（线程安全）
                {
                    {
                        std::lock_guard<std::mutex> lock(status_mutex_);
                        latest_status_ = status;
                    }
                    // 输出调试信息
                    std::cout << "收到有效状态: ";
                    if (status.flag == 0x01) 
                    {
                        std::cout << "上位机发送物块信息(颜色和坐标)" << std::endl;
                    } 
                    else if(status.flag == 0x02)
                    {
                        std::cout << " 发送场地圆 " << std::endl;
                    }
                    else if(status.flag == 0x03)
                    {
                        std::cout << " 发送靶心圆 " << std::endl;
                    }
                    else if (status.flag == 0x11) 
                    {
                        std::cout << "上位机发送信息" << std::endl;
                    }
                    else 
                    {
                        std::cout << "未知标志位: 0x" << std::hex << static_cast<int>(status.flag) << std::dec << std::endl;
                    }

                    // 清除已解析的帧（从帧头到帧尾，共3字节）
                    for (; header_pos < receive_buffer.size(); ++header_pos) 
                    {
                        if (receive_buffer[header_pos] == 0xFE) 
                            break;
                    }
                    // std::cout << "clear buffer" << std::endl;
                    // receive_buffer.erase(receive_buffer.begin(), receive_buffer.begin() + header_pos + 3);
                    receive_buffer.clear();
                } 
                else if (receive_buffer.size() > 1024) 
                {
                    // 缓冲区过大且无有效数据，防止溢出
                    receive_buffer.clear();
                }
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    });
}

SerialStatus SerialPort::parseStatus(const std::vector<uint8_t>& buffer) 
{
    SerialStatus result{};
    result.valid = false;

    // 1. 查找帧头0xFE
    size_t header_pos = buffer.size();
    for (size_t i = 0; i < buffer.size(); ++i) 
    {
        if (buffer[i] == 0xFE) // 帧头
        {  
            header_pos = i;
            break;
        }
    }
    if (header_pos == buffer.size()) 
    {
        return result;  // 未找到帧头
    }

    // 检查帧结构是否完整（帧头+标志位+帧尾，共3字节）
    if (header_pos + 2 >= buffer.size()) 
    {
        return result;  // 数据长度不足
    }

    // 验证帧尾0xFF
    if (buffer[header_pos + 2] != 0xFF) 
    {
        return result;  // 帧尾不正确
    }

    // 提取状态标志位（帧头后第1个字节）
    result.flag = buffer[header_pos + 1];
    // std::cout << "buffer: " << buffer.size() << "   ";
    // for (size_t i = 0; i < buffer.size(); ++i) 
    // {
    //     std::cout << i << "-" << buffer[i] << " ";
    // }
    // std::cout << std::endl;
    result.valid = true;
    return result;
}

void SerialPort::stop() 
{
    keep_running_ = false;
    if (read_thread_.joinable()) 
    {
        read_thread_.join();
    }
}
